package org.jeecg.client.tcp;

import lombok.extern.slf4j.Slf4j;
import org.jeecg.client.*;
import me.zhyd.oauth.log.Log;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

/**
 * @author bright
 * 到服务器的TCP连接
 */
@Slf4j
public class TCPClient implements IBizCommand {
    static int TIMEOUT = 100 * 60 * 1000;
    static int TIMEOUT_CONN = 100 * 1000;
	static byte[] HEADER;

	static {
		HEADER = "CHINT".getBytes();
	}

	private String name;
	private String ip;
	private int port;

	public TCPClient(String name, String args){
		this.name = name;
		String[] _args = args.split(":");
		this.ip = _args[1];
		this.port = Integer.parseInt(_args[2]);
	}

	/* (non-Javadoc)
	 * @see org.jeecg.client.IBizCommand#RunCmd(org.jeecg.client.BizRequest)
	 */
	@Override
	public BizResponse RunCmd(BizRequest request) {
		try {
			log.info("------------->调用一次服务器TCP");
			String client = "";
			if (Objects.nonNull(request.getClientId())){
				client = request.getClientId();
			}
			String lineServerIp = getLineServerIp(client);
			String[] _args = lineServerIp.split(":");
			String ip = _args[0];
			int port = Integer.parseInt(_args[1]);
			Socket sock = open(ip,port);
			try{
				//Socket sock = open(ip,port);
				send(sock, 1, request.toString());
				InputStream is = new BufferedInputStream(sock.getInputStream());
				int method = receiveHeader(is);
				if (1 != method)
					throw new Exception(String.format("Received method [%d] is not match runcmd.", method));
				String responseStr = receive(is);
				log.info("------------->返回结果{}",responseStr.length());
				return BizResponse.Parse(responseStr);
			}catch (Exception ex){
				ex.printStackTrace();
			}finally {
				sock.close();
			}
		} catch (Exception ex) {
			return new BizResponse(BizResponse.ServerUnreachable, ex.getMessage());
		}
		return BizResponse.Parse("");
	}

	@Override
	public DataSet RunDbCmd(BizRequest request) throws Exception {
		Log.debug("*********************************************访问DB");
		String lineServerIp = getLineServerIp(request.getClientId());
		String[] _args = lineServerIp.split(":");
		String ip = _args[1];
		int port = Integer.parseInt(_args[2]);
		Socket sock = open(ip,port);
		send(sock, 2, request.toString());
		InputStream is = new BufferedInputStream(sock.getInputStream());
		int method = receiveHeader(is);
		if (2 != method)
			throw new Exception(String.format("Received method [%d] is not match runcmd.", method));
		String responseStr = receive(is);
		sock.close();
		DataSet ds = DataSet.Parse(responseStr);
		DataTable errorTable = ds.getTable("error");
		if (null != errorTable){
			throw new Exception(String.format("MidWare server exception: %s",
					errorTable.getRows().get(0).getString("message")));
		}
		return ds;
	}

	protected Socket open(String ip,int port) throws IOException{
		Socket sock = new Socket();
		InetSocketAddress addr = new InetSocketAddress(ip, port);
		sock.setSoTimeout(TIMEOUT);
		sock.connect(addr, TIMEOUT_CONN);
		return sock;
	}

	protected void send(Socket sock, int method, String request) throws IOException{
		byte[] buf = request.getBytes();
		BufferedOutputStream os = new BufferedOutputStream(sock.getOutputStream());
		os.write(HEADER);
		os.write(method);
		os.write(buf.length & 0xff);
		os.write(buf.length >> 8 & 0xff);
		os.write(buf.length >> 16 & 0xff);
		os.write(buf.length >> 24 & 0xff);
		os.write(buf);
		os.flush();
	}

	protected int receiveHeader(InputStream is) throws IOException{
		byte[] buf = new byte[6];
		readFully(is,buf);
		for(int i = 0; i < 5; i++)
			if (HEADER[i] != buf[i])
				throw new IOException("Invalid header");

		return (int)buf[5];
	}

	protected String receive(InputStream is) throws IOException{
		byte[] lenBytes = new byte[4];
		readFully(is, lenBytes); // 确保读取4字节长度头
		int length = (lenBytes[0] & 0xFF) |
				((lenBytes[1] & 0xFF) << 8) |
				((lenBytes[2] & 0xFF) << 16) |
				((lenBytes[3] & 0xFF) << 24);
		byte[] data = new byte[length];
		readFully(is, data); // 确保读取完整数据体
		return new String(data, "UTF-8");
	}

	// 确保读取指定字节数的工具方法
	private void readFully(InputStream in, byte[] buffer) throws IOException {
		int totalRead = 0;
		while (totalRead < buffer.length) {
			int read = in.read(buffer, totalRead, buffer.length - totalRead);
			if (read == -1) throw new EOFException(
					"Expected " + buffer.length + " bytes, got " + totalRead
			);
			totalRead += read;
		}
	}

	protected String receive2(InputStream is) throws IOException{
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
		StringBuffer sf = new StringBuffer();
		String s = null;
		while ((s =bufferedReader.readLine())!=null){
			sf.append(new String(s.getBytes(),"UTF-8"));
		}

		String substring = sf.toString().substring(sf.indexOf("<"));
		System.out.println(substring);
		return substring;
	}

	protected String receive3(InputStream inStream) throws IOException{
		System.out.println("方法开始:*************************************");
		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inStream.read(buffer)) != -1) {
			//System.out.println(System.currentTimeMillis());
			String s = new String(buffer, "UTF-8");
			//System.out.println("b:"+s);
			outSteam.write(buffer, 0, len);
			System.out.println(System.currentTimeMillis());
			//System.out.println(new String(outSteam.toByteArray(), "UTF-8"));
			String b = new String(buffer, "UTF-8");
			System.out.println("e:" + b);
		}
		outSteam.close();
		inStream.close();
		String sf = new String(outSteam.toByteArray(), "UTF-8");
		String substring = sf.toString().substring(sf.indexOf("<"));
		System.out.println("方法结束:*************************************");
		return substring;
	}

	public String getLineServerIp(String client) throws Exception {
		String filePath = System.getProperty("user.dir") + "/resource/midw-client.properties";
		// 加载配置文件
		Properties prop = new Properties();
		InputStream is = null;
		// 创建File对象
		File file = new File(filePath);
		if (file.exists()) {
			is = new FileInputStream(filePath);
		} else {
			is = ClientMng.class.getResourceAsStream("/midw-client.properties");
		}
		try {
			if (is == null)
				throw new IOException("Midware client config is not exists.");
			prop.load(is);
		} finally {
			if (is != null) {
				is.close();
			}
		}
		// 加载配置参数
		String[] split = client.split(";");
		String ip = prop.getProperty(split[0]);
		if (Objects.isNull(ip)){
			return prop.getProperty("default");
		}
		return ip;
	}


}
